package script
{
	public class Lex
	{
		/**
		 * 被解析的单词列表
		 */
		private var _words:Vector.<Token>;
		
		/**
		 * 当前正在分析的单词
		 */
		private var word:String;
		
		/**
		 * 
		 */
		private var str:String;
		
		/**
		 * 行列表
		 */
		private var lines:Vector.<String>;
		
		/**
		 * 当前索引
		 */
		private var curLineIndex:int;
		
		/**
		 * 当前字符索引
		 */
		private var curChIndex:int;
		
		/**
		 * 当前字符
		 */
		private var ch:String;
		
		public function Lex(str:String){
			if(str){
				//统一换行符
				str=str.replace(/\r\n/g,"\n");
				str=str.replace(/\r/g,"\n");
				
				this.str=str;
				
				_words=new Vector.<Token>();
				
				lines=Vector.<String>(str.split("\n"));
				curLineIndex=0;
				
				nextChar();
				
				var len:int=str.length;
				var tk:Token;
				while(curChIndex <= len){
					try{
						tk=getNextWord();
						
						tk.lineIndex=curLineIndex;
						tk.lineStr=lines[curLineIndex];
					}catch(e:Error){
						
					}
					
					if(tk){
						_words.push(tk);
					}
				}
			}
		}
		
		/**
		 * 指向下一个字符
		 * @return 
		 * 
		 */
		private function nextChar():String{
			ch=str.charAt(curChIndex++);
			/*汉字的unicode编码范围
			\u4e00-\u9fa5
			A-Z,65-90,a-z,97-122;
			0-9,48-57*/
			return ch;
		}
		
		/**
		 * 读取一个字符串
		 * @return 
		 * 
		 */
		private function readString():String {
			// the token for the string we'll try to read the string to store the string we'll try to read
			var s:String = "";
			// advance past the first "
			var mychar:String=ch;
			//-------------
			nextChar();
			while ( ch != mychar && ch != '' ) {
				// unescape the escape sequences in the string
				if ( ch == '\\' ) {
					// get the next character so we know what to unescape
					nextChar();
					switch ( ch ) {
						case '"': // quotation mark
							s += '"';
							break;
						case '/':	// solidus
							s += "/";
							break;
						case '\\':	// reverse solidus
							s += '\\';
							break;
						case 'b':	// bell
							s += '\b';
							break;
						case 'f':	// form feed
							s += '\f';
							break;
						case 'n':	// newline
							s += '\n';
							break;
						case 'r':	// carriage return
							s += '\r';
							break;
						case 't':	// horizontal tab
							s += '\t'
							break;
						default:
							// couldn't unescape the sequence, so just pass it through
							s += '\\' + ch;
					}
				} else {
					// didn't have to unescape, so add the character to the string
					s += ch;
				}
				// move to the next character
				nextChar();
			}
			// we read past the end of the string without closing it, which is a parse error
			if ( ch == '' ) {
				parseError( "Unterminated string literal" );
			}
			// move past the closing " in the input string
			nextChar();
			// attach to the string to the token so we can return it
			return s;
		}
		
		/**
		 * 是否为空白字符
		 * @param ch
		 * @return 
		 * 
		 */
		private function isWhiteSpace( ch:String ):Boolean {
			return (ch==' ' || ch == '　' || ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
		}
		
		/**
		 * 是否为数字
		 * @param ch
		 * @return 
		 * 
		 */
		private function isDigit( ch:String ):Boolean {
			return ( ch >= '0' && ch <= '9' );
		}
		
		/**
		 * 是否为字母
		 * @param c
		 * @return 
		 * 
		 */
		private function isAlpha(c:String):Boolean{
			var v:Number=c.charCodeAt(0);
			
			if(v<127){
				if((v<91 && v>64)|| (v>96 && v<123) || v==95){//小写字母//大写字母//下划线
					return true;
				}
			}else{
				if(v>=0x4e00 && v<=0x9fa5){
					return true;
				}
			}
			return false;
		}
		
		/**
		 * 跳过空白字符
		 * 
		 */
		private function skipWhite():void {
			while(isWhiteSpace(ch)){
				if(ch=='\n'){
					curLineIndex++;
				}
				nextChar();
			}
		}
		
		/**
		 * 跳过注释
		 * @return 
		 * 
		 */
		private function skipComments():void{
			while ( ch == '/' ) {
				nextChar();
				switch ( ch ) {
					case "/"://行注释
						do{
							nextChar();
						}while(ch != "\n");
						break;
					case "*"://块注释
						nextChar();
						while ( true ) {
							if ( ch == '*' ) {
								nextChar();
								if ( ch == '/') {
									nextChar();
									break;
								}
							} else {
								if(ch=="\n"){
									curLineIndex++;
								}
								nextChar();
							}
							
							//到文本结尾了
							if ( ch == '' ) {
								parseError( "Multi-line comment not closed" );
							}
						}
						break;
					default://不是注释回到起点
						curChIndex -= 2;
						nextChar();
						break;
				}
			}
		}
		
		/**
		 * 跳过需要忽略的内容
		 * 
		 */
		private function skipIgnored():void {
			skipWhite();
			var c:int=0;
			while(skipComments() && c<40){
				c++;
				skipWhite();
			}
		}
		
		private function getNextWord():Token{
			skipIgnored();
			var token:Token=new Token();
			// examine the new character and see what we have...
			var cc:String;
			var nc:String;
			switch ( ch ) {
				case '{':
					token.type = TokenType.LBRACE;
					token.word = '{';
					token.value=token.word;
					nextChar();
					break
				
				case '}':
					token.type = TokenType.RBRACE;
					token.word = '}';
					token.value=token.word;
					nextChar();
					break
				
				case '(':
					token.type = TokenType.LParent;
					token.word= '(';
					token.value=token.word;
					nextChar();
					break
				
				case ')':
					token.type = TokenType.RParent;
					token.word= ')';
					token.value=token.word;
					nextChar();
					break
				
				case '.':
					token.type = TokenType.DOT;
					token.word = '.';
					token.value=token.word;
					nextChar();
					break
				
				case ';':
					token.type = TokenType.Semicolon;
					token.word = ';';
					token.value=token.word;
					nextChar();
					break
				
				case ',':
					token.type = TokenType.COMMA;
					token.word = ',';
					token.value=token.word;
					nextChar();
					break;
				
				case '-':
				case '+':
					cc=ch;
					nc=this.str.charAt(curChIndex);
					//trace(nc);
					if(nc=="="){
						token.type = TokenType.Assign;
						token.word= ch+"=";
						token.value=token.word;
						nextChar();
						nextChar();
					}else if(cc==nc){
						//++,--
						token.type = TokenType.INCREMENT;
						token.word= ch+ch;
						token.value=token.word;
						nextChar();
						nextChar();
					}else{
						token.type = TokenType.MOP;
						token.word= ch;
						token.value=token.word;
						nextChar();
					}
					break;
				
				case '*':
				case '/':
				case '%':
					cc=ch;
					
					nc=this.str.charAt(curChIndex);
					//trace(nc);
					if(nc == "="){
						token.type = TokenType.Assign;
						token.word= ch+"=";
						token.value=token.word;
						nextChar();
						nextChar();
					}else{
						token.type = TokenType.MOP;
						token.word= ch;
						token.value=token.word;
						nextChar();
					}
					break;
				
				case '&':
					nc=this.str.charAt(curChIndex);
					if(nc=="&"){
						nextChar();
						token.type = TokenType.LOP;
						token.word = "&&";
						token.value=token.word;
						nextChar();
					}else{
						//位与
						token.type = TokenType.MOP;
						token.word= ch;
						token.value=token.word;
						nextChar();
					}
					break;
				case '|':
					nc=this.str.charAt(curChIndex);
					if(nc=="|"){
						nextChar();
						token.type = TokenType.LOP;
						token.word = "||";
						token.value=token.word;
						nextChar();
					}else{
						//位或
						token.type = TokenType.MOP;
						token.word = ch;
						token.value=token.word;
						nextChar();
					}
					break;
				case '[':
					token.type = TokenType.LBRACKET;
					token.word = '[';
					token.value=token.word;
					nextChar();
					break
				case ']':
					token.type = TokenType.RBRACKET;
					token.word = ']';
					token.value=token.word;
					nextChar();
					break
				case ':':
					token.type = TokenType.Colon;
					token.word= ':';
					token.value=token.word;
					nextChar();
					break;
				case '!':
					nextChar();
					if(ch=="="){
						token.type = TokenType.COP;
						token.word = "!=";
						token.value=token.word;
						nextChar();
					}else{
						//逻辑非？单元操作符
						token.type = TokenType.LOPNot;
						token.word= "!";
						token.value=token.word;
					}
					break;
				case '=':
					nextChar();
					if(ch=="="){
						token.type = TokenType.COP;
						token.word = "==";
						token.value=token.word;
						nextChar();
					}else{
						token.type = TokenType.Assign;
						token.word = "=";
						token.value=token.word;
					}
					break;
				case '>':
					nextChar();
					if(ch=="="){
						token.type = TokenType.COP;
						token.word = ">=";
						token.value=token.word;
						nextChar();
					}else if(ch=='>'){
						token.type = TokenType.MOP;
						token.word = ">>";
						token.value=token.word;
						nextChar();
					}else{
						token.type = TokenType.COP;
						token.word = ">";
						token.value=token.word;
					}
					break;
				case '<':
					nextChar();
					if(ch=="="){
						token.type = TokenType.COP;
						token.word= "<=";
						token.value=token.word;
						nextChar();
					}else if(ch=='<'){
						token.type = TokenType.MOP;
						token.word = "<<";
						token.value=token.word;
						nextChar();
					}else{
						token.type = TokenType.COP;
						token.word = "<";
						token.value=token.word;
					}
					break;
				//字符串常量
				case '\"': // the start of a string
					token.word=readString();
					token.value=token.word;
					token.type=TokenType.constant;
					break;
				case "'": // the start of a string
					token.word=readString();
					token.value=token.word;
					token.type=TokenType.constant;
					break;
				case "#": // the start of a string
					nextChar();
					word="";
					while (isDigit(ch) || (ch>='a' && ch<='f')|| (ch>='A' && ch<='F')) {
						word+=ch;
						nextChar();
					}
					token.word=word;
					token.value=uint(parseInt(word,16));
					token.type=TokenType.constant;
					break;
				default: 
					// see if we can read a number
					if ( isDigit( ch ) || ch == '-' ) {
						//数字
						word=ch;
						nextChar();
						if(ch=="x" && word=="0"){
							//无符号的16进制数
							nextChar();
							word="";
							while (isDigit(ch) || (ch>='a' && ch<='f')|| (ch>='A' && ch<='F')) {
								word+=ch;
								nextChar();
							}
							token.word=word;
							token.value=uint(parseInt(word,16));
							token.type=TokenType.constant;
						}else{
							var ischar:Boolean=false;
							
							while (ch=='_' || isDigit(ch) || ch==".") {
								if(ch=='_'){
									ischar=true;
									//shword+='_';
								}
								word+=ch;
								nextChar();
							}
							if(ischar){
								token.word=word;
								//特殊ident
								token.value=word;
								token.type=TokenType.ident;
							}else{
								token.word=word;
								//数字常量
								token.value=Number(word);
								token.type=TokenType.constant;
							}
						}
					}else if (isAlpha(ch)) {
						word=ch;
						nextChar();
						//  || ch == '.'
						while (isAlpha(ch) || isDigit(ch) || ch == '_') {// || ch == '/'
							word+=ch;
							nextChar();
						}
						if(word.charAt(word.length-1)=='.'){
							parseError("ID不允许后后缀");
						}
						token.word=word;
						token.value=word.split('.');
						//trace(token.value);
						if(Token.isKeyWord(word)){
							if(word=="as" || word=="is" ||  word=="in" || word=="instanceof"){//关系运算符(比较运算符)
								token.type=TokenType.COP;
								token.word=word;
							}else{
								token.type=TokenType["key"+word];
							}
						}else{
							if(token.word=="false"){
								token.type=TokenType.constant;
								token.value=false;
								token.word="false";
							}else if(token.word=="true"){
								token.type=TokenType.constant;
								token.value=true;
								token.word="true";
							}else if(token.word=="null"){
								token.type=TokenType.constant;
								token.value=null;
								token.word="null";
							}else{
								token.type=TokenType.ident;
							}
						}
					}
					else if ( ch == '' ) {
						// check for reading past the end of the string
						return null;
					}else {
						// not sure what was in the input string - it's not
						// anything we expected
						parseError(curChIndex+ "Unexpected " + str.substr(curChIndex) + " encountered" );
					}
			}
			return token;
		}
		
		/**
		 * 转换错误信息
		 * @param message
		 * 
		 */
		private function parseError( message:String ):void {
			throw new Error(lines[curLineIndex]+"词法分析出错:"+message+"当前位置="+ curChIndex);
		}
		
		/**
		 * 被解析的单词列表
		 * @return 
		 * 
		 */
		public function get words():Vector.<Token>{
			return _words;
		}
	}
}